/*
 * AJC-XMEGA
 * Main.c
 *
 *  Created on: Jun 27, 2011
 *      Author: ben
 */
#ifndef F_CPU
	#define F_CPU 	32768000
#endif

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <stdio.h>

#include "avr_compiler.h"
#include "usart.h"
#include "usart_2.h"
#include "clksys_driver.h"
#include "em_406a.h"
#include "s_glcd.h"
#include "port_driver.h"

#define TRUE		0xFF
#define FALSE		0x00
#define ON			0xFF
#define OFF			0x00
#define EVEN		0x55
#define ODD			0xAA

#define BTN0		0x01
#define BTN1		0x02
#define BTN2		0x04
#define BTN3		0x08
#define LED0		0x40
#define LED1		0x80

#define BTN0_PORT	&PORTA
#define BTN1_PORT	&PORTA
#define BTN2_PORT	&PORTA
#define BTN3_PORT	&PORTA
#define LED0_PORT	&PORTF
#define LED1_PORT	&PORTF

/** Menu State Definitions **/
#define MAIN_MENU	0x00
#define GPS_MENU	0x01
#define TEMP_MENU	0x02
#define CAR_MENU	0x03
#define MAIN_MORE	0x04
#define AMP_MENU	0x05
#define MAIN_CONF	0x06

#define GPS_MORE	0x07
#define AMP_MORE	0x08

//#define BAUD_RATE 115200
//#define UBRRVAL ((F_CPU/(BAUD_RATE*16UL))-1)
#define RECEIVED_DATA_SIZE 8

static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
//static FILE lcdout = FDEV_SETUP_STREAM(onWriteStatusPrintF, NULL, _FDEV_SETUP_WRITE);

int main(void);
void ClkInit(void);
void IoInit(void);
void DrawScreen(void);
void SetLED(PORT_t *port, char led, int state);
void DataInit(void);
void MenuChange(int button, int state);

/** GPS Controls **/
volatile GPS_DATA gpsData;
volatile int gpsEnable = 0;
volatile int updatePosition = 0;

/** LCD Control **/
volatile int reDrawScreen = 0;

/** State Controls **/
volatile int stateTransition = 0;
volatile int cstate = 0;
volatile int nstate = 0;
//cstate = 0 -> Main Menu
//cstate = 1 -> GPS Menu


int main()
{
	IoInit();
	ClkInit();
	SetLED(LED0_PORT, LED0, ON);
	SetLED(LED1_PORT, LED1, ON);
	_delay_ms(400);
	SetLED(LED0_PORT, LED0, OFF);
	SetLED(LED1_PORT, LED1, OFF);

	onClearScreen();
	DataInit();
	onMainMenu();

	while(1)
	{
		if (GPS_MENU & updatePosition & gpsEnable)
		{
			onLoadingScreen();
			onWriteStatus(">Updating Position");
			gpsData = GPSGetCoord();
			reDrawScreen = 1;
			updatePosition = 0;
		}

		if (stateTransition)
		{
			onLoadingScreen();
			onWriteStatus(">Changing State");
			cstate = nstate;
			reDrawScreen = 1;
			stateTransition = 0;
		}

		if (reDrawScreen)
			DrawScreen();

	}
}

void ClkInit()
{
	CLKSYS_Enable( OSC_RC32MEN_bm ); //32MHz
	CLKSYS_Prescalers_Config( CLK_PSADIV_1_gc, CLK_PSBCDIV_1_1_gc );
	do {} while ( CLKSYS_IsReady( OSC_RC32MRDY_bm ) == 0 );
	CLKSYS_Main_ClockSource_Select( CLK_SCLKSEL_RC32M_gc );
	CLKSYS_Disable(OSC_RC2MCREF_bm);
	CLKSYS_AutoCalibration_Enable(OSC_RC32MCREF_bm,1);
}

void IoInit()
{
	PORTF.DIRSET = 0xC0;

	//USART
	usart_init(&PORTC, &USARTC0, 4800);
	usart_init_2(&PORTC, &USARTC1, 115200);
	stdout = &mystdout;
	usart_rx_buf_flush();
	usart_rx_buf_flush_2();

	//Interrupt
	PORT_ConfigurePins(	&PORTA, 0x01, FALSE, FALSE, PORT_OPC_PULLDOWN_gc,
			PORT_ISC_RISING_gc);
	PORT_ConfigurePins(BTN1_PORT, BTN1, FALSE, FALSE, PORT_OPC_PULLDOWN_gc,
				PORT_ISC_RISING_gc);
	PORT_ConfigurePins(BTN2_PORT, BTN2, FALSE, FALSE, PORT_OPC_PULLDOWN_gc,
					PORT_ISC_RISING_gc);
	PORT_ConfigurePins(BTN3_PORT, BTN3, FALSE, FALSE, PORT_OPC_PULLDOWN_gc,
					PORT_ISC_RISING_gc);
	PORT_SetPinsAsInput(BTN0_PORT, BTN0);
	PORT_SetPinsAsInput(BTN1_PORT, BTN1);
	PORT_SetPinsAsInput(BTN2_PORT, BTN2);
	PORT_SetPinsAsInput(BTN3_PORT, BTN3);
	PORT_ConfigureInterrupt0( &PORTA, PORT_INT0LVL_MED_gc, 0x0F);
	PMIC.CTRL |= PMIC_MEDLVLEN_bm;


//	PORT_ConfigureInterrupt1(BTN1_PORT, PORT_INT1LVL_MED_gc, 0x08);
//	PMIC.CTRL |= PMIC_MEDLVLEN_bm;

	sei();
}

void DrawScreen(void)
{
	switch (cstate)
	{
	case MAIN_MENU:
		onWriteStatus("Drawing Screen:0");
		onMainMenu();
		break;

	case GPS_MENU:
		onWriteStatus("Drawing Screen:1");
		onGPSMenu();
		if (gpsData.fixErr == 1)
		{
			onWriteStatus(">GPS ERROR!");
		}
		else
		{
			onSetLCDLatitude(gpsData.latitude, gpsData.NS);
			onSetLCDLongitude(gpsData.longitude, gpsData.EW);
		}
		break;

	case CAR_MENU:
		onWriteStatus("Drawing Screen:3");
		onCarMenu();
		break;

	case GPS_MORE:
		onWriteStatus("Drawing Screen:7");
		onGPSMore();
		break;

	case MAIN_MORE:
		onWriteStatus("Drawing Screen:4");
		onMainMore();
		break;

	case TEMP_MENU:
		onWriteStatus("Drawing Screen:2");
		onTempMenu();
		break;
	}

	reDrawScreen = 0;
}

void SetLED(PORT_t *port, char led, int state)
{
	if (state)
		port->OUTSET = (led & ON);
	else
		port->OUTCLR = (led & TRUE);
}

void DataInit(void)
{
	onLoadingScreenBar();
	onUpdateLoadingBar(21);
	onWriteStatus("#GPS_DATA");
	if (gpsEnable)
		gpsData = GPSGetCoord();
	onUpdateLoadingBar(42);
}

void MenuChange(int button, int state)
{
	switch (state)
	{
	case MAIN_MENU:
		switch (button)
		{
		case BTN0:
			nstate = GPS_MENU;
			updatePosition = 1;
			break;

		case BTN1:
			nstate = CAR_MENU;
			break;

		case BTN2:
			nstate = TEMP_MENU;
			break;

		case BTN3:
			nstate = MAIN_MORE;
			break;
		}
		break;

	case GPS_MENU:
		switch (button)
		{
		case BTN0:
			nstate = MAIN_MENU;
			updatePosition = 0;
			break;

		case BTN1:
			nstate = GPS_MORE;
			updatePosition = 0;
			break;
		}
		break;

	case CAR_MENU:
		switch (button)
		{
		case BTN0:
			nstate = MAIN_MENU;
			break;
		}
		break;

	case TEMP_MENU:
		switch (button)
		{
		case BTN0:
			nstate = MAIN_MENU;
			break;
		}
		break;

	case MAIN_MORE:
		switch (button)
		{
		case BTN0:
			nstate = MAIN_MENU;
			break;

		case BTN1:
			nstate = AMP_MENU;
			break;

		case BTN2:
			nstate = MAIN_CONF;
			break;
		}
		break;
	}
	reDrawScreen = 1;
	stateTransition = 1;
}

ISR(PORTA_INT0_vect)
{
	_delay_ms(200);
	uint8_t btnValue = PORT_GetPortValue(&PORTA);
	if (btnValue & BTN0)
		MenuChange(BTN0, cstate);
	else if (btnValue & BTN1)
		MenuChange(BTN1, cstate);
	else if (btnValue & BTN2)
		MenuChange(BTN2, cstate);
	else if (btnValue & BTN3)
		MenuChange(BTN3, cstate);
//	default:
//		SetLED(LED1_PORT, LED0, ON);
//		SetLED(LED1_PORT, LED1, ON);
//		_delay_ms(500);
//		SetLED(LED1_PORT, LED0, OFF);
//		SetLED(LED1_PORT, LED1, OFF);
//		break;

//	switch (cstate)
//	{
//	case MAIN_MENU:
////		onGPSMenu();
////		_delay_ms(100);
////		gpsData = GPSGetCoord();
////		onSetLCDLatitude(gpsData.latitude);
////		onSetLCDLongitude(gpsData.longitude);
//		nstate = GPS_MENU;
//		updatePosition = 1;
////		while (PORT_GetPortValue(&PORTA) == 1) {};
//		break;
//
//	case GPS_MENU:
////		onMainMenu();
////		_delay_ms(100);
//		nstate = MAIN_MENU;
//		updatePosition = 0;
////		while (PORT_GetPortValue(&PORTA) == 1) {};
//		break;
//
//	case CAR_MENU:
//		nstate = MAIN_MENU;
//		break;
//
//	case GPS_MORE:
//		nstate = GPS_MENU;
//		updatePosition = 0;
//		break;
//
////	default:
////		onMainMenu();
////		cstate = 0;
////		break;
//	}
//	reDrawScreen = 1;
//	stateTransition = 1;
}

//ISR(PORTA_INT1_vect)
//{
//	_delay_ms(200);
//	switch (cstate)
//	{
//	case MAIN_MENU:
////		onGPSMenu();
////		_delay_ms(100);
////		gpsData = GPSGetCoord();
////		onSetLCDLatitude(gpsData.latitude);
////		onSetLCDLongitude(gpsData.longitude);
//		nstate = CAR_MENU;
////		while (PORT_GetPortValue(&PORTA) == 1) {};
//		break;
//
//	case GPS_MENU:
////		onMainMenu();
////		_delay_ms(100);
//		nstate = GPS_MORE;
//		updatePosition = 0;
////		while (PORT_GetPortValue(&PORTA) == 1) {};
//		break;
//
////	default:
////		onMainMenu();
////		cstate = 0;
////		break;
//	}
//	reDrawScreen = 1;
//	stateTransition = 1;
//}
